from godot import exposed, export
from godot import *
from threading import Thread
from time import sleep
from nio import HttpClient
from nio import Api, LoginError, RegisterResponse, JoinError, RoomVisibility, LoginResponse
from nio import MessageDirection, RoomMessagesResponse, RoomMessagesError

import requests
import asyncio
from queue import SimpleQueue
from nio import Api, events

class WorkerThread(Thread):
    def __init__(self,_mc):
        super().__init__()
        self.mc = _mc
        self.room_name = '' 
        print("initting the thread")
    def run(self):
        do_work( self.mc, self.room_name )

def do_work(mc, room_name):
    print("worker is invoked")
    while True:
        mc.fetch_new_messages(room_name)
        sleep(0.1)
        #print("still running, yeah")

@exposed
class MatrixClient(Node2D):

    # member variables here, example:
    a = export(int)
    thread = False
    homeserver = export(str, default='some.server')
    username = ''
    client: HttpClient = None
    syncing = False
    token = False
    batch = 0
    q: SimpleQueue = None

    def _ready(self):
        print("hello, godot-python")
        self.thread = WorkerThread(self)
        self.homeserver = str(self.homeserver)
        self.username = str(self.username)
        print(self.homeserver, self.username)
        self.client = HttpClient(self.homeserver, self.username)
        self.q = SimpleQueue()
        #thread.start()

    def register(self, password):
        base_url = self.homeserver

        (_ignored, path, data) = Api.register(self.username,str(password), 'GODOT')
        result =requests.post(base_url+path,data= data, verify=False)

        print(result)
        if result.status_code != 200:
            return False
        return True

    def login(self, password):

        self.client.connect()

        result = self.client.login(str(password))

        print(result)
        if isinstance(result, LoginError):
            return False
        return True

    def login2(self, password):
        base_url = self.homeserver

        (_ignored, path, data) = Api.login(self.username,str(password), 'GODOT')
        result =requests.post(base_url+path,data= data, verify=False)

        self.token = result.json()["access_token"]
        print("token ", self.token)
        if result.status_code != 200:
            return False
        return True

    def create_if_not(self, _room_name):
        room_name = str(_room_name)
        create_res = self.client.room_create(
                RoomVisibility.public,
                alias=room_name,
                name=room_name)
        print("creation result", create_res)

    def create_if_not2(self, _room_name):
        room_name = str(_room_name)
        base_url = self.homeserver

        (_ignored, path, data) = Api.room_create(
                self.token,
                RoomVisibility.public,
                alias=room_name,
                name=room_name)
        result =requests.post(base_url+path,data= data, verify=False)
        print("creation result", result.json())
        if result.status_code != 200 and not 'IN_USE' in result.json()['errcode']:
            return False
        return True

    def resolve(self, room_alias):
        pass

    def join(self, room_id_or_alias):
        room_name = str(_room_name)
        joinres= client.join(room_alias)
        print(joinres)
        if isinstance(new_joinres, JoinError):
            return False
        return True

    def join2(self, room_id_or_alias):
        room_name = str(room_id_or_alias)
        base_url = self.homeserver

        (_ignored, path, data) = Api.join(
                self.token,room_name)
        result =requests.post(base_url+path,data= data, verify=False)
        print("join result", result, result.json())
        print(result.status_code)
        if result.status_code != 200:
            return False
        return result.json()['room_id']

    def get_first_batch(self):
        print("sending a sync")
        base_url = self.homeserver
        (_ignored, path) = Api.sync(self.token)
        result =requests.get(base_url+path, verify=False)
        print("sync result", result)
        if result.status_code != 200:
            return False
        self.batch = result.json()["next_batch"]

    def start_listen(self, room_id):
        self.thread.room_name = room_id
        self.thread.start()

    def fetch_new_messages(self,room_id):
        room_name = str(room_id)
        base_url = self.homeserver

        (_ignored, path) = Api.room_messages(self.token, room_name, self.batch, direction=MessageDirection.front)
        result =requests.get(base_url+path, verify=False)
        #print("messages result", result, result.json().keys())
        rmr: RoomMessagesResponse = RoomMessagesResponse.from_dict(result.json(), room_id)
        if isinstance(rmr, RoomMessagesError):
            return False

        self.batch = rmr.end
        print ("batch ", self.batch)
        for e in rmr.chunk:
            #print ("received event of type ", e.source['type'])
            if e.source['type'] != 'm.room.message':
                continue
            room_msg: RoomMessageText = events.Event.parse_event(e.source)
            print("received message ", room_msg.body)
            self.q.put(room_msg.body)

        if result.status_code != 200:
            return False
        return True

    def fetch_one(self):
        if not self.q.empty():
            return self.q.get()
        else:
            return ''





